package top.ninwoo.edgecenter.service.impl;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;
import top.ninwoo.common.entity.NetworkTopology;
import top.ninwoo.edgecenter.service.ClusterService;
import top.ninwoo.edgecenter.service.IpService;
import top.ninwoo.edgecenter.service.LogicTopoService;
import top.ninwoo.utils.service.IptablesService;

import java.util.ArrayList;
import java.util.List;
import java.util.Set;
import java.util.concurrent.ConcurrentHashMap;

@Service
public class LogicTopoServiceImpl implements LogicTopoService {
    private final static Logger LOG = LoggerFactory.getLogger(TopologyServiceImpl.class);
    // 用于存储集群的拓扑
    private ConcurrentHashMap<Long, NetworkTopology> clustersTopo = new ConcurrentHashMap<>();
    //根据appnames来存储IP
    private ConcurrentHashMap<Long, List<String>> clustersIPlist = new ConcurrentHashMap<>();

    @Autowired
    private ClusterService clusterService;

    @Autowired
    private IpService ipService;

    @Autowired
    private IptablesService iptablesService;

    @Override
    public String creatLogicTopo(long clusterId, NetworkTopology oldtopo) {
        List<String> IPlist = new ArrayList<String>();
        NetworkTopology logictopo = this.getLogictopo(oldtopo);

        if (logictopo == null) {
            LOG.warn("集群[" + clusterId + "]未设置网络");
            return "集群创建失败";
        }

        // 校验信息
        String[] cNames = logictopo.getAppNames();
        int[][] topo = logictopo.getTopology();
        if (cNames == null || cNames.length <= 1) {
            return "集群创建失败";
        }

        for(int k=0;k<cNames.length;k++){
            Set<String> cid = clusterService.getContainerIdsByClusterId(clusterId, cNames[k]);
            if (cid == null){
                System.out.println("错误的clusterID");
                return "获取失败";
            }
            String appID = ((String) cid.toArray()[0]);
            if(appID ==null){
                System.out.println("错误的appnmae");
                return "获取失败";
            }
            String appIP = ipService.getContainerIp(appID).split("/")[0];

            IPlist.add(appIP);
        }
        clustersTopo.put(clusterId, logictopo);
        clustersIPlist.put(clusterId,IPlist);
        return "success";
    }

    @Override
    public String modifyLogicTopology(long clusterId, NetworkTopology oldtopo) {
        NetworkTopology logictopo = this.getLogictopo(oldtopo);
        // 先进行校验
        if (logictopo == null) {
            LOG.error("topoloy不能为空");
            return "topoloy不能为空";
        }

        // 获取clusterId的网络拓扑
        if (!clustersTopo.containsKey(clusterId)) {
            System.out.println("该集群没有设置topo");
            return "该集群没有设置topo";
        }

        NetworkTopology origTopo = clustersTopo.get(clusterId);
        // 校验topoId是否一致
        if (origTopo.getTopologyId() != logictopo.getTopologyId()) {
            LOG.error("不是相同的网络拓扑，无法更改");
            return "不是相同的网络拓扑，无法更改";
        }

        // 校验成员名称是否相同
        for (int i = 0; i < origTopo.getAppNames().length; i++) {
            if (!origTopo.getAppNames()[i].equals(logictopo.getAppNames()[i])) {
                LOG.error("App名称必须一致");
                return "App名称必须一致";
            }
        }

        int[][] origTopoArr = origTopo.getTopology();
        int[][] newTopoArr = logictopo.getTopology();
        // 校验topo是否一致
        if ((origTopoArr.length != newTopoArr.length)
                || (origTopoArr[0].length != newTopoArr[0].length)) {
            LOG.error("拓扑大小不一致");
            return "拓扑大小不一致";
        }
        clustersTopo.put(clusterId, logictopo);

        return "success";
    }

    @Override
    public NetworkTopology getLogictopo(NetworkTopology oritopo) {
        NetworkTopology logictopo = new NetworkTopology();

        int flag = 0;
        //获取appnames
        for (int i = 0; i < oritopo.getAppNames().length - 1; i++) {
            if (oritopo.getAppNames()[i].startsWith("br:")) {
                break;
            }
            flag++;
        }
        String[] appname = new String[flag];
        for(int k=0;k<flag;k++){appname[k]=oritopo.getAppNames()[k];}
        logictopo.setAppNames(appname);

        //获取逻辑拓扑
        int[][] logicTopo = new int[flag][flag];
        for (int j=1;j<flag;j++){
            for (int m=0;m<j;m++){logicTopo[j][m] = oritopo.getTopology()[j][m];}
        }
        logictopo.setTopology(logicTopo);

        logictopo.setTopologyId(oritopo.getTopologyId());

        return logictopo;
    }


    public void addDelDropIPtable(long clusterId, String appName1, String appName2) {
        //获取容器ID
        Set<String> cid1 = clusterService.getContainerIdsByClusterId(clusterId, appName1);
        String appID1 = ((String) cid1.toArray()[0]);
        String appIP1 = ipService.getContainerIp(appID1).split("/")[0];
        Set<String> cid2 = clusterService.getContainerIdsByClusterId(clusterId, appName2);
        String appID2 = ((String) cid2.toArray()[0]);
        String appIP2 = ipService.getContainerIp(appID2).split("/")[0];
        //dropTraffic(String containerId, String sourceIp, String destinationIp)
        //dropTraffic模块      容器ID       源（容器）地址      目的（容器）地址
        iptablesService.cancelDropTraffic(appID1, appIP2, appIP1);
        iptablesService.cancelDropTraffic(appID2, appIP1, appIP2);
    }

    public void addDropIPtable(long clusterId, String appName1, String appName2) {
        //获取容器ID
        Set<String> cid1 = clusterService.getContainerIdsByClusterId(clusterId, appName1);
        String appID1 = ((String) cid1.toArray()[0]);
        String appIP1 = ipService.getContainerIp(appID1).split("/")[0];
        Set<String> cid2 = clusterService.getContainerIdsByClusterId(clusterId, appName2);
        String appID2 = ((String) cid2.toArray()[0]);
        String appIP2 = ipService.getContainerIp(appID2).split("/")[0];
        //dropTraffic(String containerId, String sourceIp, String destinationIp)
        //dropTraffic模块      容器ID       源（容器）地址      目的（容器）地址
        iptablesService.dropTraffic(appID1, appIP2, appIP1);
        iptablesService.dropTraffic(appID2, appIP1, appIP2);
    }

    @Override
    public int[][] getTopo(long clusterId) {
        if(!clustersTopo.containsKey(clusterId)){
            LOG.error("没有该集群的Topo");
            return null;
        }
        return clustersTopo.get(clusterId).getTopology();
    }

    @Override
    public List<String> getIPlist(long clusterId) {
        if(!clustersIPlist.containsKey(clusterId)){
            LOG.error("没有该集群的IPlist");
            return new ArrayList<String>();
        }
        return clustersIPlist.get(clusterId);
    }
}
